/*
 Licensed to the Apache Software Foundation (ASF) under one or more
 contributor license agreements.  See the NOTICE file distributed with
 this work for additional information regarding copyright ownership.
 The ASF licenses this file to You under the Apache License, Version 2.0
 (the "License"); you may not use this file except in compliance with
 the License.  You may obtain a copy of the License at

     http://www.apache.org/licenses/LICENSE-2.0

 Unless required by applicable law or agreed to in writing, software
 distributed under the License is distributed on an "AS IS" BASIS,
 WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
 See the License for the specific language governing permissions and
 limitations under the License.
*/

var zk_error = function zk_error( xhr, text_status, error_thrown )
{
  var zk = null;
  try
  {
    eval( 'zk = ' + xhr.responseText + ';' );
  }
  catch( e ) {}

  var message = '<p class="txt">Loading of "<code>' + xhr.url + '</code>" '
              + 'failed (HTTP-Status <code>' + xhr.status + '</code>)</p>' + "\n";

  if( zk.error )
  {
    message += '<p class="msg">"' + zk.error.esc() + '"</p>' + "\n";
  }
  
  this.closest( '#cloud' )
    .html( '<div class="block" id="error">' + message + '</div>' );
};

var init_debug = function( cloud_element )
{
  var debug_element = $( '#debug', cloud_element );
  var debug_button = $( '#menu #cloud .dump a' );

  var clipboard_element = $( '.clipboard', debug_element );
  var clipboard_button = $( 'a', clipboard_element );

  debug_button
    .die( 'click' )
    .live
    (
      'click',
      function( event )
      {
        debug_element.trigger( 'show' );
        return false;
      }
    );

  $( '.close', debug_element )
    .die( 'click' )
    .live
    (
      'click',
      function( event )
      {
        debug_element.trigger( 'hide' );
        return false;
      }
    );

  $( '.clipboard', debug_element )
    .die( 'click' )
    .live
    (
      'click',
      function( event )
      {
        return false;
      }
    );

  debug_element
    .die( 'show' )
    .live
    (
      'show',
      function( event )
      {
        debug_element.show();

        $.ajax
        (
          {
            url : app.config.solr_path + '/zookeeper?wt=json&dump=true',
            dataType : 'text',
            context : debug_element,
            beforeSend : function( xhr, settings )
            {
              $( '.debug', debug_element )
                .html( '<span class="loader">Loading Dump ...</span>' );

              ZeroClipboard.setMoviePath( 'img/ZeroClipboard.swf' );

              clipboard_client = new ZeroClipboard.Client();
                              
              clipboard_client.addEventListener
              (
                'load',
                function( client )
                {
                }
              );

              clipboard_client.addEventListener
              (
                'complete',
                function( client, text )
                {
                  clipboard_element
                    .addClass( 'copied' );

                  clipboard_button
                    .data( 'text', clipboard_button.text() )
                    .text( clipboard_button.data( 'copied' ) );
                }
              );
            },
            success : function( response, text_status, xhr )
            {
              clipboard_client.glue
              (
                clipboard_element.get(0),
                clipboard_button.get(0)
              );

              clipboard_client.setText( response.replace( /\\/g, '\\\\' ) );

              $( '.debug', debug_element )
                .removeClass( 'loader' )
                .text( response );
            },
            error : function( xhr, text_status, error_thrown )
            {
            },
            complete : function( xhr, text_status )
            {
            }
          }
        );
      }
    )
    .die( 'hide' )
    .live
    (
      'hide',
      function( event )
      {
        $( '.debug', debug_element )
          .empty();

        clipboard_element
          .removeClass( 'copied' );

        clipboard_button
          .data( 'copied', clipboard_button.text() )
          .text( clipboard_button.data( 'text' ) );

        clipboard_client.destroy();

        debug_element.hide();
      }
    );
};

var helper_path_class = function( p )
{
  var classes = [ 'link' ];
  classes.push( 'lvl-' + p.target.depth );

  if( p.target.data && p.target.data.leader )
  {
    classes.push( 'leader' );
  }

  if( p.target.data && p.target.data.state )
  {
    classes.push( p.target.data.state );
  }

  return classes.join( ' ' );
};

var helper_node_class = function( d )
{
  var classes = [ 'node' ];
  classes.push( 'lvl-' + d.depth );

  if( d.data && d.data.leader )
  {
    classes.push( 'leader' );
  }

  if( d.data && d.data.state )
  {
    classes.push( d.data.state );
  }

  return classes.join( ' ' );
};

var helper_data = {
  protocol: [],
  host: [],
  hostname: [],
  port: [],
  pathname: []
};

var helper_node_text = function( d )
{
  if( !d.data || !d.data.uri )
  {
    return d.name;
  }

  var name = d.data.uri.hostname;

  if( 1 !== helper_data.protocol.length )
  {
    name = d.data.uri.protocol + '//' + name;
  }

  if( 1 !== helper_data.port.length )
  {
    name += ':' + d.data.uri.port;
  }

  if( 1 !== helper_data.pathname.length )
  {
    name += d.data.uri.pathname;
  }

  return name;
};

var generate_graph = function( graph_element, graph_data, leaf_count )
{
  var w = graph_element.width(),
      h = leaf_count * 20;

  var tree = d3.layout.tree()
    .size([h, w - 400]);

  var diagonal = d3.svg.diagonal()
    .projection(function(d) { return [d.y, d.x]; });

  var vis = d3.select( '#canvas' ).append( 'svg' )
    .attr( 'width', w )
    .attr( 'height', h)
    .append( 'g' )
      .attr( 'transform', 'translate(100, 0)' );

  var nodes = tree.nodes( graph_data );

  var link = vis.selectAll( 'path.link' )
    .data( tree.links( nodes ) )
    .enter().append( 'path' )
      .attr( 'class', helper_path_class )
      .attr( 'd', diagonal );

  var node = vis.selectAll( 'g.node' )
    .data( nodes )
    .enter().append( 'g' )
      .attr( 'class', helper_node_class )
      .attr( 'transform', function(d) { return 'translate(' + d.y + ',' + d.x + ')'; } )

  node.append( 'circle' )
    .attr( 'r', 4.5 );

  node.append( 'text' )
    .attr( 'dx', function( d ) { return 0 === d.depth ? -8 : 8; } )
    .attr( 'dy', function( d ) { return 5; } )
    .attr( 'text-anchor', function( d ) { return 0 === d.depth ? 'end' : 'start'; } )
    .attr( 'data-href', function( d ) { return d.name; } )
    .text( helper_node_text );

  $( 'text[data-href*="//"]', graph_element )
    .die( 'click' )
    .live
    (
      'click',
      function()
      {
        location.href = $( this ).data( 'href' );
      }
    );
};

var generate_rgraph = function( graph_element, graph_data, leaf_count )
{
  var max_val = Math.min( graph_element.width(), $( 'body' ).height() )
  var r = max_val / 2;

  var cluster = d3.layout.cluster()
    .size([360, r - 160]);

  var diagonal = d3.svg.diagonal.radial()
    .projection(function(d) { return [d.y, d.x / 180 * Math.PI]; });

  var vis = d3.select( '#canvas' ).append( 'svg' )
    .attr( 'width', r * 2 )
    .attr( 'height', r * 2 )
    .append( 'g' )
      .attr( 'transform', 'translate(' + r + ',' + r + ')' );

  var nodes = cluster.nodes( graph_data );

  var link = vis.selectAll( 'path.link' )
    .data( cluster.links( nodes ) )
    .enter().append( 'path' )
      .attr( 'class', helper_path_class )
      .attr( 'd', diagonal );

  var node = vis.selectAll( 'g.node' )
    .data( nodes )
    .enter().append( 'g' )
      .attr( 'class', helper_node_class )
      .attr( 'transform', function(d) { return 'rotate(' + (d.x - 90) + ')translate(' + d.y + ')'; } )

  node.append( 'circle' )
    .attr( 'r', 4.5 );

  node.append( 'text' )
    .attr( 'dx', function(d) { return d.x < 180 ? 8 : -8; } )
    .attr( 'dy', '.31em' )
    .attr( 'text-anchor', function(d) { return d.x < 180 ? 'start' : 'end'; } )
    .attr( 'transform', function(d) { return d.x < 180 ? null : 'rotate(180)'; } )
    .attr( 'data-href', function( d ) { return d.name; } )
    .text( helper_node_text );

  $( 'text[data-href*="//"]', graph_element )
    .die( 'click' )
    .live
    (
      'click',
      function()
      {
        location.href = $( this ).data( 'href' );
      }
    );
};

var prepare_graph = function( graph_element, callback )
{
  $.ajax
  (
    {
      url : app.config.solr_path + '/zookeeper?wt=json&path=%2Flive_nodes',
      dataType : 'json',
      success : function( response, text_status, xhr )
      {
        var live_nodes = {};
        for( var c in response.tree[0].children )
        {
          live_nodes[response.tree[0].children[c].data.title] = true;
        }

        $.ajax
        (
          {
            url : app.config.solr_path + '/zookeeper?wt=json&detail=true&path=%2Fclusterstate.json',
            dataType : 'json',
            context : graph_element,
            beforeSend : function( xhr, settings )
            {
              this
                .show();
            },
            success : function( response, text_status, xhr )
            {
              var state = null;
              eval( 'state = ' + response.znode.data + ';' );
              
              var leaf_count = 0;
              var graph_data = {
                name: null,
                children : []
              };

              for( var c in state )
              {
                var shards = [];
                for( var s in state[c].shards )
                {
                  var nodes = [];
                  for( var n in state[c].shards[s].replicas )
                  {
                    leaf_count++;
                    var replica = state[c].shards[s].replicas[n]

                    var uri = replica.base_url;
                    var parts = uri.match( /^(\w+:)\/\/(([\w\d\.-]+)(:(\d+))?)(.+)$/ );
                    var uri_parts = {
                      protocol: parts[1],
                      host: parts[2],
                      hostname: parts[3],
                      port: parseInt( parts[5] || 80, 10 ),
                      pathname: parts[6]
                    };
                    
                    helper_data.protocol.push( uri_parts.protocol );
                    helper_data.host.push( uri_parts.host );
                    helper_data.hostname.push( uri_parts.hostname );
                    helper_data.port.push( uri_parts.port );
                    helper_data.pathname.push( uri_parts.pathname );

                    var status = replica.state;

                    if( !live_nodes[replica.node_name] )
                    {
                      status = 'gone';
                    }

                    var node = {
                      name: uri,
                      data: {
                        type : 'node',
                        state : status,
                        leader : 'true' === replica.leader,
                        uri : uri_parts
                      }
                    };
                    nodes.push( node );
                  }

                  var shard = {
                    name: s,
                    data: {
                      type : 'shard'
                    },
                    children: nodes
                  };
                  shards.push( shard );
                }

                var collection = {
                  name: c,
                  data: {
                    type : 'collection'
                  },
                  children: shards
                };
                graph_data.children.push( collection );
              }
              
              helper_data.protocol = $.unique( helper_data.protocol );
              helper_data.host = $.unique( helper_data.host );
              helper_data.hostname = $.unique( helper_data.hostname );
              helper_data.port = $.unique( helper_data.port );
              helper_data.pathname = $.unique( helper_data.pathname );

              callback( graph_element, graph_data, leaf_count );
            },
            error : function( xhr, text_status, error_thrown)
            {
            },
            complete : function( xhr, text_status )
            {
            }
          }
        );
      },
      error : function( xhr, text_status, error_thrown)
      {
      },
      complete : function( xhr, text_status )
      {
      }
    }
  );

};

var init_graph = function( graph_element )
{
  prepare_graph
  (
    graph_element,
    function( graph_element, graph_data, leaf_count )
    {
      generate_graph( graph_element, graph_data, leaf_count );
    }
  );
}

var init_rgraph = function( graph_element )
{
  prepare_graph
  (
    graph_element,
    function( graph_element, graph_data, leaf_count )
    {
      generate_rgraph( graph_element, graph_data, leaf_count );
    }
  );
}

var init_tree = function( tree_element )
{
  $.ajax
  (
    {
      url : app.config.solr_path + '/zookeeper?wt=json',
      dataType : 'json',
      context : tree_element,
      beforeSend : function( xhr, settings )
      {
        this
          .show();
      },
      success : function( response, text_status, xhr )
      {
        var self = this;
                      
        $( '#tree', this )
          .jstree
          (
            {
              "plugins" : [ "json_data" ],
              "json_data" : {
                "data" : response.tree,
                "progressive_render" : true
              },
              "core" : {
                "animation" : 0
              }
            }
          )
          .jstree
          (
            'open_node',
            'li:first'
          );

        var tree_links = $( '#tree a', this );

        tree_links
          .die( 'click' )
          .live
          (
            'click',
            function( event )
            {
              $( 'a.active', $( this ).parents( '#tree' ) )
                .removeClass( 'active' );
                                  
              $( this )
                .addClass( 'active' );

              tree_element
                .addClass( 'show' );

              var file_content = $( '#file-content' );

              $( 'a.close', file_content )
                .die( 'click' )
                .live
                (
                  'click',
                  function( event )
                  {
                    $( '#tree a.active' )
                      .removeClass( 'active' );
                                      
                    tree_element
                      .removeClass( 'show' );

                    return false;
                  }
                );

              $.ajax
              (
                {
                  url : this.href,
                  dataType : 'json',
                  context : file_content,
                  beforeSend : function( xhr, settings )
                  {
                  },
                  success : function( response, text_status, xhr )
                  {
                    var props = [];
                    for( var key in response.znode.prop )
                    {
                      props.push
                      (
                        '<li><dl class="clearfix">' + "\n" +
                          '<dt>' + key.esc() + '</dt>' + "\n" +
                          '<dd>' + response.znode.prop[key].esc() + '</dd>' + "\n" +
                        '</dl></li>'
                      );
                    }

                    $( '#prop ul', this )
                      .empty()
                      .html( props.join( "\n" ) );

                    $( '#prop ul li:odd', this )
                      .addClass( 'odd' );

                    var data_element = $( '#data', this );

                    var highlight = false;
                    var data = '<em>Node "' + response.znode.path + '" has no utf8 Content</em>';

                    if( response.znode.data )
                    {
                      var classes = '';
                      var path = response.znode.path.split( '.' );
                      
                      if( 1 < path.length )
                      {
                        highlight = true;
                        classes = 'syntax language-' + path.pop().esc();
                      }

                      data = '<pre class="' + classes + '">'
                           + response.znode.data.esc()
                           + '</pre>';
                    }
                               

                    data_element
                        .show()
                        .html( data );

                    if( highlight )
                    {
                      hljs.highlightBlock( data_element.get(0) );
                    }
                    
                  },
                  error : function( xhr, text_status, error_thrown)
                  {
                  },
                  complete : function( xhr, text_status )
                  {
                  }
                }
              );

              return false;
            }
          );
      },
      error : zk_error,
      complete : function( xhr, text_status )
      {
      }
    }
  );
};

// #/~cloud
sammy.get
(
  /^#\/(~cloud)$/,
  function( context )
  {
    var content_element = $( '#content' );

    $.get
    (
      'tpl/cloud.html',
      function( template )
      {
        content_element
          .html( template );

        var cloud_element = $( '#cloud', content_element );
        var navigation_element = $( '#menu #cloud' );

        init_debug( cloud_element );

        $( '.tree', navigation_element )
          .die( 'activate' )
          .live
          (
            'activate',
            function( event )
            {
              $( this ).addClass( 'active' );
              init_tree( $( '#tree-content', cloud_element ) );
            }
          );

        $( '.graph', navigation_element )
          .die( 'activate' )
          .live
          (
            'activate',
            function( event )
            {
              $( this ).addClass( 'active' );
              init_graph( $( '#graph-content', cloud_element ) );
            }
          );

        $( '.rgraph', navigation_element )
          .die( 'activate' )
          .live
          (
            'activate',
            function( event )
            {
              $( this ).addClass( 'active' );
              init_rgraph( $( '#graph-content', cloud_element ) );
            }
          );

        $.ajax
        (
          {
            url : app.config.solr_path + '/zookeeper?wt=json',
            dataType : 'json',
            context : cloud_element,
            success : function( response, text_status, xhr )
            {
              $( 'a[href="' + context.path + '"]', navigation_element )
                .trigger( 'activate' );
            },
            error : zk_error
          }
        );
        
      }
    );
  }
);
